package com.notary.tx_live_plugin.widget;

import android.content.Context;
import android.os.Build;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.widget.FrameLayout;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.notary.tx_live_plugin.util.TxConstant;
import com.notary.tx_live_plugin.util.TxLogger;
import com.notary.tx_live_plugin.util.PushManager;
import com.notary.tx_live_plugin.util.VideoProcessListener;
import com.tencent.liteav.basic.log.TXCLog;
import com.tencent.rtmp.ITXLivePushListener;
import com.tencent.rtmp.TXLiveConstants;
import com.tencent.rtmp.TXLivePushConfig;
import com.tencent.rtmp.TXLivePusher;
import com.tencent.rtmp.ui.TXCloudVideoView;

import java.util.HashMap;

/**
 * 直播录像的录制控件
 */
public class TxLivePushView extends FrameLayout implements ITXLivePushListener {

    private TXCloudVideoView mVideoView;
    private TXLivePushConfig mLivePushConfig;
    private TXLivePusher mLivePusher;
    private VideoProcessListener mProcessListener;
    private PushManager.OnPushCallback mOnPushCallback;

    private boolean flashLightOpen, useFrontCamera;
    private boolean isLivePushing;

    public TxLivePushView(@NonNull Context context) {
        super(context);
        initView();
    }

    public TxLivePushView(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        initView();
    }

    public TxLivePushView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initView();
    }

    private void initView(){
        initLivePusher();
    }

    /**
     * flutter初始创建view时传递的参数
     */
    public void setParams(HashMap<String, Object> params){

    }

    public void setOnPushCallback(PushManager.OnPushCallback onPushCallback){
        this.mOnPushCallback = onPushCallback;
    }

    public void initPushView(){
        if(mVideoView == null){
            mVideoView = new TXCloudVideoView(getContext());
            addView(mVideoView);
            mLivePusher.startCameraPreview(mVideoView);
        }
    }

    public void onResume(){
        if (mVideoView != null) {
            mVideoView.onResume();
        }
        if (mLivePusher != null) {
            mLivePusher.resumePusher();
        }
    }

    public void onPause(){
        if (mVideoView != null) {
            mVideoView.onPause();
        }
        if (mLivePusher != null) {
            mLivePusher.pausePusher();
        }
    }

    /**
     * 外部通知 开始录像
     */
    public boolean startLivePush(String url, long serverTime,boolean isBitrateStandard) {
        mProcessListener.syncTime(serverTime);
        String rtmpUrl = "";
        if (!TextUtils.isEmpty(url)) { //这部分代码是拷贝直播推流demo的
            String[] urls = url.split("###");
            if (urls.length > 0) {
                rtmpUrl = urls[0];
            }
        }

        if (!rtmpUrl.startsWith("rtmp://")) {
            toast( "推流地址不合法，目前只支持rtmp推流!");
            return false;
        }
        if(mLivePusher == null) {
            toast("直播推流异常，请退出重新进入该界面");
            return false;
        }
        fixOrAdjustBitrate(isBitrateStandard);
        int i = mLivePusher.startPusher(rtmpUrl.trim());
        TxLogger.e("live push back :", i);
        if(i < 0){
            //开发文档 https://cloud.tencent.com/document/product/454/56589
            String msg = "推流报错code="+i;
            switch (i){
                case -1: msg = "暂未归类的通用错误"; break;
                case -2: msg = "调用 API 时，传入的参数不合法"; break;
                case -3: msg = "API 调用被拒绝"; break;
                case -4: msg = "当前 API 不支持调用"; break;
                case -5: msg = "license 不合法，调用失败"; break;
                case -6: msg = "腾讯请求服务器超时"; break;
                case -7: msg = "腾讯服务器无法处理您的请求"; break;
            }
            callback(TxConstant.PushMethod.Back.error,msg);
            return false;
        }
        isLivePushing = true;
        return true;
//        startTime(maxTime * 60); //服务端给的是分钟数，此处转换为秒数
//        //隐藏切换按钮 和 录制格式
//        mTvBitrate.setVisibility(View.GONE);
//        mIvSwitchCamera.setVisibility(View.GONE);
//        setBtnRecord(true);
//        setNetChange();
    }

    /**
     * 外部通知 停止录像
     */
    public void stopPush(){
        //外部已经通知服务端停止录像，发给原生停止推送、摄像头关闭
        //可以是stopLivePush通知外部，外部处理后，调用该stopPush方法，用于正在关闭摄像头等
        stopLivePush();
    }

    /**
     * 摄像头开启错误，录制过程中异常，触发的停止录像
     * @param notifyServer 是否需要通知flutter
     */
    private void stopLivePush(boolean notifyServer){
        isLivePushing = false;
        if(mLivePusher != null)mLivePusher.stopPusher();
        HashMap<String,Object> data = new HashMap<>();
        data.put(TxConstant.PushMethod.Key.cameraError,!notifyServer);//true, 需要关闭页面控件
        data.put(TxConstant.PushMethod.Key.needNoticeServer,notifyServer);//true，时要通知服务端停止录像
        callback(TxConstant.PushMethod.Back.stopLivePush,data);
    }

    private void stopLivePush(){
        isLivePushing = false;
        if(mLivePusher != null){
            mLivePusher.stopPusher();
            mLivePusher.stopCameraPreview(true);
            mLivePusher.setPushListener(null);
            mLivePusher = null;
        }
        if(mVideoView != null){
            mVideoView.onDestroy();
            mVideoView = null;
        }
    }

    /**
     * 关闭
     */
    public void onDestroy(){
        stopLivePush();
    }

    /**
     * 是否录制中
     */
    public boolean isPushing(){
        return isLivePushing || mLivePusher.isPushing();
    }

    public void turnOnFlashLight(){
        boolean flashLightOpen = !this.flashLightOpen;
        if(mLivePusher.turnOnFlashLight(flashLightOpen)) {
           this.flashLightOpen = flashLightOpen;
        }
    }

    public boolean isFlashLightOpen(){
        return this.flashLightOpen;
    }

    public boolean isFontCamera(){
        return this.useFrontCamera;
    }

    public void switchCamera(){
        if (mLivePusher == null)return;
        boolean useFrontCamera = !this.useFrontCamera;
        mLivePusher.switchCamera();//起到切换摄像头
        //设置观众端的镜像效果
        mLivePusher.setMirror(useFrontCamera);
        mLivePushConfig.setFrontCamera(useFrontCamera);
        this.useFrontCamera = useFrontCamera;
//        mIvFlashLight.setVisibility(useFrontCamera ? View.GONE : View.VISIBLE);
        if(useFrontCamera){
            flashLightOpen = false;
//            mIvFlashLight.setImageResource(R.mipmap.img_flash_light_turn_on);
        } else { //如果是后置摄像头，开启手动聚焦
            mLivePushConfig.setTouchFocus(true);
            if (mLivePusher.isPushing()) {
                toast( "已开启手动对焦");
            }
        }
    }

//    protected final void fullScreen() {
//        Window window = getWindow();
//        window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
//                WindowManager.LayoutParams.FLAG_FULLSCREEN);
//        window.setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON,
//                WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
//
//        window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE
//                | View.SYSTEM_UI_FLAG_FULLSCREEN
//                | View.SYSTEM_UI_FLAG_LAYOUT_STABLE
//                | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
//                | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
//                | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
//    }

    private void initLivePusher() {
        TXCLog.init();
        mLivePusher = new TXLivePusher(getContext());
        mLivePusher.setPushListener(this);

        mLivePushConfig = new TXLivePushConfig();
        if (Build.VERSION.SDK_INT < 18) { //使用软编码
            mLivePushConfig.setHardwareAcceleration(TXLiveConstants.ENCODE_VIDEO_SOFTWARE);
        } else { //开启硬件
            mLivePushConfig.setHardwareAcceleration(TXLiveConstants.ENCODE_VIDEO_HARDWARE);
        }
        toast("已开启手动对焦");
        //ToastUtil.showMsg( "已开启手动对焦");
        mLivePushConfig.setFrontCamera(useFrontCamera);
        mLivePusher.setConfig(mLivePushConfig);
        if(mVideoView != null)mLivePusher.startCameraPreview(mVideoView);
        mLivePusher.setVideoProcessListener(mProcessListener = new VideoProcessListener() {
            @Override
            public int onTextureCustomProcess(int textureId, int width, int height) {
                callback(TxConstant.PushMethod.Back.videoProcessListener,null);
                return super.onTextureCustomProcess(textureId, width, height);
            }
        });
    }
    /**
     * 推流开始通知
     */
    private void notifyPushStart(){
        callback(TxConstant.PushMethod.Back.notifyPushStart,null);
    }

    private void toast(String msg){
        callback(TxConstant.PushMethod.Back.toast,msg);
    }

    private void callback(String name,Object data){
        if(mOnPushCallback != null){
            mOnPushCallback.callback(name,data);
        }
    }

    private void setHardwareAcceleration(boolean software) {
        mLivePushConfig.setHardwareAcceleration(software ? TXLiveConstants.ENCODE_VIDEO_SOFTWARE :
                TXLiveConstants.ENCODE_VIDEO_HARDWARE);
        mLivePusher.setConfig(mLivePushConfig);
    }

    private void fixOrAdjustBitrate(boolean isBitrateStandard) {
        boolean autoBitrate = true;//true（表示码率范围300~800kbps）
        boolean autoResolution = false;//true(表示分辨率范围270x480 ~ 360x640)
        if(isBitrateStandard) {
            mLivePusher.setVideoQuality(TXLiveConstants.VIDEO_QUALITY_STANDARD_DEFINITION, autoBitrate, autoResolution);
            mLivePushConfig.setAutoAdjustBitrate(false);//标清默认开启了码率自适应，需要关闭码率自适应
            mLivePushConfig.setVideoBitrate(700);
            setHardwareAcceleration(true);//标清默认关闭硬件加速
        } else {
            mLivePusher.setVideoQuality(TXLiveConstants.VIDEO_QUALITY_SUPER_DEFINITION, autoBitrate, autoResolution);
            setHardwareAcceleration(Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2);
        }
    }

    @Override
    public void onPushEvent(int event, Bundle param) {
        String msg = param.getString(TXLiveConstants.EVT_DESCRIPTION);
        TxLogger.d( "receive event: " + event + ", " + msg);
        //错误还是要明确的报一下
        switch (event){
            case TXLiveConstants.PUSH_ERR_NET_DISCONNECT:
            case TXLiveConstants.PUSH_ERR_SCREEN_CAPTURE_UNSURPORT:
            case TXLiveConstants.PUSH_ERR_SCREEN_CAPTURE_START_FAILED:
                if (isLivePushing) {
                    stopLivePush(true);
                }
                break;
            case TXLiveConstants.PUSH_ERR_OPEN_CAMERA_FAIL:
                stopLivePush(false);
                //finish();
                break;
            case TXLiveConstants.PUSH_ERR_OPEN_MIC_FAIL:
                toast(msg);
                break;
            case TXLiveConstants.PUSH_WARNING_HW_ACCELERATION_FAIL://hardware acceleration fail
                setHardwareAcceleration(true);
                break;
            case TXLiveConstants.PUSH_EVT_CHANGE_RESOLUTION://change resolution
                TxLogger.d( "change resolution to " + param.getInt(TXLiveConstants.EVT_PARAM2) + ", bitrate to" + param.getInt(TXLiveConstants.EVT_PARAM1));
                break;
            case  TXLiveConstants.PUSH_EVT_CHANGE_BITRATE:
                TxLogger.d("change bitrate to" + param.getInt(TXLiveConstants.EVT_PARAM1));
                break;
            case  TXLiveConstants.PUSH_WARNING_NET_BUSY://net busy tips
                callback(TxConstant.PushMethod.Back.toastSnackBar, "当前网络质量很糟糕，建议您拉近离路由器的距离，避免WiFi穿墙！");
                TxLogger.d("net busy....");
                break;
            case TXLiveConstants.PUSH_EVT_START_VIDEO_ENCODER:
                int encType = param.getInt(TXLiveConstants.EVT_PARAM1);
                setHardwareAcceleration(encType != 1);
                break;
            case TXLiveConstants.PUSH_EVT_PUSH_BEGIN://push begin
                TxLogger.i("begin push", isLivePushing);
                if (isLivePushing == false) {
                    isLivePushing = true;
                    notifyPushStart();
                }
                break;
            default:break;
        }
    }

    @Override
    public void onNetStatus(Bundle status) {
        String str = getNetStatusString(status);
        mLivePusher.onLogRecord("[net state]:\n" + str + "\n");
    }
    //公用打印辅助函数
    protected String getNetStatusString(Bundle status) {
        return String.format("%-14s %-14s %-12s\n%-8s %-8s %-8s %-8s\n%-14s %-14s %-12s\n%-14s %-14s",
                "CPU:" + status.getString(TXLiveConstants.NET_STATUS_CPU_USAGE),
                "RES:" + status.getInt(TXLiveConstants.NET_STATUS_VIDEO_WIDTH) + "*" + status.getInt(TXLiveConstants.NET_STATUS_VIDEO_HEIGHT),
                "SPD:" + status.getInt(TXLiveConstants.NET_STATUS_NET_SPEED) + "Kbps",
                "JIT:" + status.getInt(TXLiveConstants.NET_STATUS_NET_JITTER),
                "FPS:" + status.getInt(TXLiveConstants.NET_STATUS_VIDEO_FPS),
                "GOP:" + status.getInt(TXLiveConstants.NET_STATUS_VIDEO_GOP) + "s",
                "ARA:" + status.getInt(TXLiveConstants.NET_STATUS_AUDIO_BITRATE) + "Kbps",
                "QUE:",
                "DRP:",
//                "QUE:" + status.getInt(TXLiveConstants.NET_STATUS_CODEC_CACHE) + "|" + status.getInt(TXLiveConstants.NET_STATUS_CACHE_SIZE),
//                "DRP:" + status.getInt(TXLiveConstants.NET_STATUS_CODEC_DROP_CNT) + "|" + status.getInt(TXLiveConstants.NET_STATUS_DROP_SIZE),
                "VRA:" + status.getInt(TXLiveConstants.NET_STATUS_VIDEO_BITRATE) + "Kbps",
                "SVR:" + status.getString(TXLiveConstants.NET_STATUS_SERVER_IP),
                "AUDIO:" + status.getString(TXLiveConstants.NET_STATUS_AUDIO_INFO));
    }
}
